package informationextraction;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javaparser.Java7InformationListener;
import javaparser.Java7Parser.ArgumentsContext;
import javaparser.Java7Parser.IdentifierTypeArgumentContext;
import javaparser.Java7Parser.LocalVariableDeclarationContext;
import javaparser.Java7Parser.PrimaryContext;

public class InfoExtraction {
	Java7InformationListener info = new Java7InformationListener();

	public InfoExtraction(Java7InformationListener info) {
		this.info = info;
	}

	public Java7InformationListener getInfo() {
		return info;
	}

	public List<String> getListVariableNameOfIntent() {
		List<String> list = new ArrayList<String>();
		List<LocalVariableDeclarationContext> list_local_variable_dcl = info
				.getLocal_variable_declaration();
		Iterator<LocalVariableDeclarationContext> itr = list_local_variable_dcl
				.iterator();
		while (itr.hasNext()) {
			LocalVariableDeclarationContext local_i = itr.next();
			String rule = local_i.getRuleContext().getText();
			// Error
			if (rule.contains("Intent")) {
				try {
					List<IdentifierTypeArgumentContext> list_identifier_type_argument = local_i
							.type().classOrInterfaceType()
							.identifierTypeArgument();

					Iterator<IdentifierTypeArgumentContext> itr1 = list_identifier_type_argument
							.iterator();
					while (itr1.hasNext()) {
						IdentifierTypeArgumentContext id_type = itr1.next();
						if (id_type.Identifier().getText().compareTo("Intent") == 0) {
							list.add(local_i.variableDeclarator(0).Identifier()
									.getText());
						}
					}
				} catch (NullPointerException e) {
					local_i = itr.next();
					// TODO: handle exception
				}
			}
		}
		return list;
	}

	public List<LocalVariableDeclarationContext> getListLocalVariableDeclarationOfIntent() {
		List<LocalVariableDeclarationContext> list = new ArrayList<LocalVariableDeclarationContext>();
		List<LocalVariableDeclarationContext> list_local_variable_dcl = info
				.getLocal_variable_declaration();
		Iterator<LocalVariableDeclarationContext> itr = list_local_variable_dcl
				.iterator();
		while (itr.hasNext()) {
			LocalVariableDeclarationContext local_i = itr.next();
			if (local_i.getRuleContext().getText().contains("newIntent")) {
				list.add(local_i);
			}

		}
		return list;
	}

	// Usually has one LocalVariableDeclarationContext object in list
	public List<LocalVariableDeclarationContext> getListLocalVariableDeclarationOfIntent(
			String variable_name) {
		List<LocalVariableDeclarationContext> list = new ArrayList<LocalVariableDeclarationContext>();
		List<LocalVariableDeclarationContext> list_local_variable_dcl = info
				.getLocal_variable_declaration();
		Iterator<LocalVariableDeclarationContext> itr = list_local_variable_dcl
				.iterator();
		List<LocalVariableDeclarationContext> list_intent = new ArrayList<LocalVariableDeclarationContext>();
		// Iterator<LocalVariableDeclarationContext> itr1 =
		// list_intent.iterator();
		// Error
		while (itr.hasNext()) {
			LocalVariableDeclarationContext local_i = itr.next();
			String rule = local_i.getRuleContext().getText();
			if (rule.contains("Intent"))
				list_intent.add(local_i);
		}
		for (int i = 0; i < list_intent.size(); i++) {
			// LocalVariableDeclarationContext local = itr1.next();
			// String rule = local.getRuleContext().getText();

			if (list_intent.get(i).variableDeclarator(0).Identifier().getText()
					.compareTo(variable_name) == 0)

				list.add(list_intent.get(i));
		}

		return list;
	}

	public List<PrimaryContext> getListMethodCallOfIntentVariables() {
		List<PrimaryContext> list = new ArrayList<PrimaryContext>();
		List<PrimaryContext> list_primary = info.getList_primary();
		Iterator<PrimaryContext> itr = list_primary.iterator();
		List<String> variable_name_intent = getListVariableNameOfIntent();
		while (itr.hasNext()) {
			PrimaryContext local_i = itr.next();
			for (int i = 0; i < variable_name_intent.size(); i++) {
				String start = variable_name_intent.get(i) + ".";
				if (local_i.getRuleContext().getText().startsWith(start)) {
					list.add(local_i);
				}
			}

		}
		return list;
	}

	public List<PrimaryContext> getListMethodCallOfIntentVariablesContainsComponentName() {
		List<PrimaryContext> list = new ArrayList<PrimaryContext>();
		List<PrimaryContext> list_primary = info.getList_primary();
		Iterator<PrimaryContext> itr = list_primary.iterator();
		List<String> variable_name_intent = getListVariableNameOfIntent();
		while (itr.hasNext()) {
			PrimaryContext local_i = itr.next();
			for (int i = 0; i < variable_name_intent.size(); i++) {
				String start = variable_name_intent.get(i) + ".";
				if (local_i.getRuleContext().getText().startsWith(start)
						&& local_i.getRuleContext().getText()
								.contains("ComponentName")) {
					list.add(local_i);
				}
			}

		}
		return list;
	}

	// Return list of PrimaryContext objects which contains ComponentName method
	// Usually has one LocalVariableDeclarationContext object in list
	public List<PrimaryContext> getListMethodCallOfIntentVariablesContainsComponentName(
			String variable_name) {
		List<PrimaryContext> list = new ArrayList<PrimaryContext>();
		List<PrimaryContext> list_primary = info.getList_primary();
		Iterator<PrimaryContext> itr = list_primary.iterator();
		List<String> variable_name_intent = getListVariableNameOfIntent();
		while (itr.hasNext()) {
			PrimaryContext local_i = itr.next();
			if (local_i.getRuleContext().getText()
					.startsWith(variable_name + ".")
					&& local_i.getRuleContext().getText()
							.contains("ComponentName"))
				list.add(local_i);
		}
		return list;
	}

	public List<PrimaryContext> getListMethodCallOfIntentVariablesContainsSetActionMethod(
			String variable_name) {
		List<PrimaryContext> list = new ArrayList<PrimaryContext>();
		List<PrimaryContext> list_primary = info.getList_primary();
		Iterator<PrimaryContext> itr = list_primary.iterator();
		List<String> variable_name_intent = getListVariableNameOfIntent();
		while (itr.hasNext()) {
			PrimaryContext local_i = itr.next();
			if (local_i.getRuleContext().getText()
					.startsWith(variable_name + ".")
					&& local_i.getRuleContext().getText().contains("setAction"))
				list.add(local_i);
		}
		return list;
	}

	public List<PrimaryContext> getListMethodCallOfIntentVariablesContains(
			String variable_name, String str) {
		List<PrimaryContext> list = new ArrayList<PrimaryContext>();
		List<PrimaryContext> list_primary = info.getList_primary();
		Iterator<PrimaryContext> itr = list_primary.iterator();
		// List<String> variable_name_intent = getListVariableNameOfIntent();
		while (itr.hasNext()) {
			PrimaryContext local_i = itr.next();
			if (local_i.getRuleContext().getText()
					.startsWith(variable_name + ".")
					&& local_i.getRuleContext().getText().contains(str))
				list.add(local_i);
		}
		return list;
	}

	public String getAction(String variable) {
		String action_name = null;

		List<PrimaryContext> list_ctx = getPrimaryContextFromArgumentContextOfIntentVariable(variable);
		if (list_ctx.isEmpty()) {

			// case 1:
			// Intent intent_variable = new Intent();
			// intent_variable.setAction(Intent.ACTION_)
			List<PrimaryContext> list_pri = getListMethodCallOfIntentVariablesContainsSetActionMethod(variable);
			if (!list_pri.isEmpty()) {
				action_name = getActionName(list_pri.get(0));
				return action_name;
			}
			// must be modified:
			// case 2:
			// default action in xml file tag intentAction
			return "GET IT IN ANDROIDMANIFEST.XML";
		}
		Iterator<PrimaryContext> itr = list_ctx.iterator();
		while (itr.hasNext()) {
			PrimaryContext pri = itr.next();
			if (pri.getRuleContext().getText().contains("ACTION_")) {
				action_name = pri.Identifier(1).getText();
			}
		}
		return action_name;
	}

	private String getActionName(PrimaryContext primaryContext) {
		// TODO Auto-generated method stub
		String str = primaryContext.getRuleContext().getText();
		int id1 = str.indexOf("(");
		int id2 = str.indexOf(")");
		String full = str.substring(id1, id2);
		return full.substring(full.indexOf(".") + 1, full.length());
	}

	// Get PrimaryContext object from ArgumentContext of an Intent's variable
	public List<PrimaryContext> getPrimaryContextFromArgumentContextOfIntentVariable(
			String variable_name) {
		List<PrimaryContext> list_pri = new ArrayList<PrimaryContext>();
		ArgumentsContext arg = getArgumentsContextOfIntentVariable(variable_name);
		// Intent intent = getIntent() -->
		// getArgumentsContextOfIntentVariable("intent"); --> ()
		String rule = arg.getRuleContext().getText(); // --> ()
		Iterator<PrimaryContext> itr = info.getList_primary().iterator();
		while (itr.hasNext()) {
			PrimaryContext ctx = itr.next();
			if (rule.contains(ctx.getRuleContext().getText()))
				list_pri.add(ctx);
		}
		return list_pri;
	}

	public ArgumentsContext getArgumentsContextOfIntentVariable(
			String variable_name) {
		ArgumentsContext arg = null;
		// Error
		try {
			String rule = getListLocalVariableDeclarationOfIntent(variable_name)
					.get(0).getRuleContext().getText();
			Iterator<ArgumentsContext> itr = info.getList_argrument()
					.iterator();
			while (itr.hasNext()) {
				ArgumentsContext ctx = itr.next();
				if (rule.contains(ctx.getRuleContext().getText())) {
					return ctx;
				}
			}
		} catch (IndexOutOfBoundsException e) {
			// TODO: handle exception
			return arg;
		}
		return arg;
	}
}
